package com.wyz.saas.common.map

import android.graphics.Bitmap
import android.util.SparseArray
import androidx.core.util.forEach
import androidx.core.util.set
import com.atom.map.WorldHelper
import com.atom.map.WorldWind
import com.atom.map.geom.Position
import com.atom.map.geom.SimpleColor
import com.atom.map.layer.AbstractLayer
import com.atom.map.layer.RenderableLayer
import com.atom.map.renderable.ImageSource
import com.atom.map.renderable.Placemark
import com.atom.map.renderable.Renderable
import com.atom.map.renderable.attribute.PlacemarkAttributes
import com.atom.map.renderable.attribute.ShapeAttributes
import com.atom.map.renderable.attribute.TextAttributes
import com.atom.map.renderable.shape.Ellipse
import com.atom.map.renderable.shape.Label
import com.atom.map.renderable.shape.Path
import com.atom.map.renderable.shape.Polygon
import com.atom.annotation.Impl
import com.atom.api.ApiContext
import com.atom.api.ApiContextAware
import com.wyz.saas.api.map.MapOverlayManager
import com.wyz.saas.api.map.MapOverlayProducer
import com.wyz.saas.api.map.shape.*
import com.wyz.saas.common.R
import java.lang.Exception
import kotlin.collections.HashMap

@Impl(api = MapOverlayManager::class)
class MapOverlayManagerImpl : MapOverlayManager, ApiContextAware {

    // api 环境
    private lateinit var mApiImplContext: ApiContext

    // 地图控件
    private var mMap: WorldHelper? = null

    // 图层和对应的地图图层软链接
    private val mMapOverlayProducers: HashMap<AbstractLayer, MapOverlayProducer?> = hashMapOf()

    override fun setApiContextAware(context: ApiContext) {
        this.mApiImplContext = context
        context.getApis(MapOverlayProducer::class.java)
            .forEach {
                try {
                    context.newApi(it)?.also { producer ->
                        val annotation = producer.javaClass.getAnnotation(Impl::class.java)
                        mMapOverlayProducers[RenderableLayer().apply {
                            this.displayName = annotation?.name ?: producer.javaClass.name
                        }] = producer
                    }
                } catch (e: Exception) {
                    context.report("MapOverlayManagerImpl" , e)
                }
            }
    }

    override fun setMapView(map: Any?) {
        if (map is WorldHelper) {
            // 添加layer
            this.mMap = map
            this.onCreate()
            mMapOverlayProducers.forEach {
                map.getMapLayers().addLayer(it.key) // 将地图图层添加添加到地图上
                it.value?.setProducerListener( // 设置地图的回调
                    SimpleProductorListener(it.key as RenderableLayer)
                )
            }
        }
        if (map == null) {
            // 清空layer
            mMapOverlayProducers.forEach {
                this.mMap?.getMapLayers()?.removeLayer(it.key)
                it.value?.setProducerListener(null)
            }
            this.mMap = null
            this.onDestroy()
        }
    }

    inner class SimpleProductorListener : MapOverlayProducer.ProducerListener {
        // 地图空间的图层
        private val layer: RenderableLayer

        // 地图空间图层的shape 图素
        private val cacheShapeOverlayer: HashMap<Any, SparseArray<ShapeOverlayer>>

        constructor(layer: RenderableLayer) {
            this.layer = layer
            this.cacheShapeOverlayer = hashMapOf()
        }

        override fun notifice(key: Any, mapOverlay: SparseArray<MapOverlay>) {
            // 获取该图层上的 图素 根据指定的key
            // 图素可能是若干组成的 比如图标point 和 标题label
            var sparseArray = cacheShapeOverlayer[key]
            if (sparseArray == null) {
                sparseArray = SparseArray()
                cacheShapeOverlayer[key] = sparseArray
            }
            mapOverlay.forEach { idx, value ->
                var get = sparseArray.get(idx)
                if (get == null) {
                    get = ShapeOverlayer()
                    sparseArray.setValueAt(idx, get)
                }
                if (value.getEnabled()) {
                    // true 可见 可以进行添加或者更新
                    insertOrUpdate(get, value)
                } else {
                    // false 设置不可见,进行回收
                    get.shape?.also { readable ->
                        layer.removeRenderable(readable)
                    }
                    // 进行初始化操作
                    get.reset()
                }
            }
            // 地图控件进行重新绘制
            requestRenderer()
        }

        override fun setEnabled(enabled: Boolean) {
            layer.enabled = enabled
            // 地图控件进行重新绘制
            requestRenderer()
        }

        private fun insertOrUpdate(shape: ShapeOverlayer, overlay: MapOverlay) {
            if (shape.isNULL()) {
                // 添加一个shape 点 线 面 文字 园
                // 检查 overlayer 是啥属性根据不同属性 添加不同shape
                shape.set(overlay)?.also {
                    layer.addRenderable(it)
                }
            } else if (shape.isNotNULL()) {
                shape.set(overlay)
            } else {
                // 重新添加 将旧的从rendererlayer 移除
                shape.shape?.also {
                    layer.removeRenderable(it)
                }
                insertOrUpdate(shape.reset(), overlay)
            }
        }
    }

    private fun requestRenderer() {
        mMap?.requestRedraw()
    }

    class ShapeOverlayer {
        var overlay: MapOverlay? = null
        var shape: Renderable? = null

        fun isNULL(): Boolean = overlay == null && shape == null
        fun isNotNULL(): Boolean = overlay != null && shape != null
        fun reset(): ShapeOverlayer {
            overlay = null
            shape = null
            return this
        }

        fun set(overlay: MapOverlay): Renderable? {
            when (overlay.getType()) {
                "ELLIPSE" -> (overlay as MapOverlayEllipse).also { overlayEllipse ->
                    val coordinate = overlayEllipse.getGeometry().coordinate
                    shape = shape?.apply {
                        (this as Ellipse).also {
                            it.center.set(coordinate.y, coordinate.x, coordinate.z)
                            it.majorRadius = overlayEllipse.getBuffer().toDouble()
                            it.minorRadius = overlayEllipse.getBuffer().toDouble()
                        }
                    } ?: Ellipse(
                        Position(coordinate.y, coordinate.x, coordinate.z),
                        overlayEllipse.getBuffer().toDouble(),
                        overlayEllipse.getBuffer().toDouble(),
                        ShapeAttributes.defaults().apply {
                            this.interiorColor = (SimpleColor(overlayEllipse.getFillColor())) // 50% transparent white
                            this.drawVerticals = true
                        }
                    ).apply {
                        if (overlayEllipse.isExtrude()) {
                            this.extrude = (true)
                        } else {
                            this.altitudeMode = (WorldWind.CLAMP_TO_GROUND)
                            this.followTerrain = (true)
                        }
                    }
                }
                "LABEL" -> (overlay as MapOverlayLabel).also { overlayLabel ->
                    val coordinate = overlayLabel.getGeometry().coordinate
                    shape = shape?.apply {
                        (this as Label).also {
                            it.position.set(coordinate.y, coordinate.x, coordinate.z)
                            it.text = overlayLabel.getText()
                        }
                    } ?: Label(
                        Position(coordinate.y, coordinate.x, coordinate.z),
                        overlayLabel.getText(),
                        TextAttributes.defaults().apply {
                            this.drawLeader = overlayLabel.isExtrude()
                        }
                    )
                }
                "POINT" -> (overlay as MapOverlayPoint).also { overlayPoint ->
                    val coordinate = overlayPoint.getGeometry().coordinate
                    shape = shape?.apply {
                        (this as Placemark).also {
                            it.position.set(coordinate.y, coordinate.x, coordinate.z)
                            it.attributes.imageSource = ImageSource.fromBitmap(overlayPoint.getIcon())
                        }
                    } ?: Placemark(
                        Position(coordinate.y, coordinate.x, coordinate.z),
                        PlacemarkAttributes.withImage(
                            ImageSource.fromBitmap(overlayPoint.getIcon())
                        )
                    )
                }
                "POLYGON" -> (overlay as MapOverlayPolygon).also { overlayPolygon ->
                    val list = mutableListOf<Position>()
                    overlayPolygon.getGeometry().coordinates.forEachIndexed { index, coordinate ->
                        list.add(index, Position(coordinate.y, coordinate.x, coordinate.z))
                    }
                    shape = shape?.apply {
                        (this as Polygon).also {
                            this.clearBoundaries()
                            it.boundaries.add(list)
                        }
                    } ?: Polygon(list).apply {
                        this.altitudeMode = (WorldWind.CLAMP_TO_GROUND)
                        this.followTerrain = (true)
                    }
                }
                "POLYLINE" -> (overlay as MapOverlayPolyline).also { overlayPolyline ->
                    val list = mutableListOf<Position>()
                    overlayPolyline.getGeometry().coordinates.forEachIndexed { index, coordinate ->
                        list.add(index, Position(coordinate.y, coordinate.x, coordinate.z))
                    }
                    shape = shape?.apply {
                        (this as Path).also {
                            it.positions = list
                        }
                    } ?: Path(list, ShapeAttributes.defaults().apply {
                        this.outlineColor = SimpleColor.random()
                    }).apply {
                        this.altitudeMode = (WorldWind.CLAMP_TO_GROUND)
                        this.followTerrain = (true)
                    }
                }
            }
            this.overlay = overlay
            return shape
        }
    }

    override fun onCreate() {
        mMapOverlayProducers.forEach {
            it.value?.onCreate()
        }
    }

    override fun onStart() {
        mMapOverlayProducers.forEach {
            it.value?.onStart()
        }
    }

    override fun onStop() {
        mMapOverlayProducers.forEach {
            it.value?.onStop()
        }
    }

    override fun onDestroy() {
        mMapOverlayProducers.forEach {
            it.value?.onDestroy()
        }
    }

    override fun overlayers(): List<MapOverlayManager.MapOverlay> {
        val keys = mMapOverlayProducers.keys
        val temp = mutableListOf<MapOverlayManager.MapOverlay>()
        keys.iterator().forEach {
            temp.add(object : MapOverlayManager.MapOverlay {
                override fun display(): String {
                    return it.displayName
                }

                override fun isEnabled(): Boolean {
                    return it.enabled
                }

                override fun enable(boolean: Boolean) {
                    it.enabled = boolean
                    mMap?.requestRedraw()
                }

                override fun icon(): Bitmap? {
                    return mApiImplContext.getBitmap(R.mipmap.air_fixwing)
                }
            })
        }
        return temp
    }
}